/*jslint vars: true, forin: true, sloppy: true */
/*global angular, console */
(function (angular) {
	var OAs = angular.module('oc-APIs', []);

	var keyParamReg = /\$(\d)/g, getKey = function (keySet, args) {
		return keySet.replace(keyParamReg, function (argIndex) {
			return args[Number(argIndex.charAt(1))];
		});
	};

	var API = function API(APIName, options) {
		if (!(this instanceof API)) {
			return new API(APIName, options);
		}
		if (this.has(APIName)) {
			throw new Error('API:' + APIName + ' is existed!');
		}

		this.request = options.request;
		this.cacheKey = options.cacheKey;
		this.interceptor = options.interceptor || [];
		this.filter = options.filter || [];

		// Save API to this.APIs.
		this.APIs[APIName] = this;
	}, $AP = API.prototype;
	$AP.APIOrigin = '';
	// Storage & manage APIs.
	$AP.APIs = {};
	// Storage & manage APIs.
	$AP.filters = {};
	// Storage & manage APIs.
	$AP.interceptors = {};
	// Try to search API by name.
	$AP.has = function (APIName) {
		return this.APIs.hasOwnProperty(APIName);
	};

	OAs.provider('ocAPI', [function () {

		this.$get = [
			'$q', '$http', '$cacheFactory', '$rootScope',
			function ($q, $http, $cacheFactory, $rootScope) {
				$rootScope.ocAPI = {};
				$rootScope.ocAPI.timeStamp = Date.now();
				$rootScope.ocAPI.getNow = function () {
					$rootScope.ocAPI.timeStamp = Date.now();
				};

				// Create cacheFactory.
				$AP.cache = $cacheFactory('ocAPIsCache');

				$AP.by = function (primaryKey) {
					var deffered = $q.defer(),
						// [A]PI[I]nterceptor
						AI = this.interceptor,
						// [A]PI[F]ilter
						AF = this.filter;

					var key = this.cacheKey && getKey(this.cacheKey + (primaryKey || ''), arguments);

					if (key && this.cache.get(key)) {
						// 配置了缓存并且有缓存记录就从缓存里取数据
						deffered.resolve(this.cache.get(key));
					} else {
						this.request.apply(this, arguments).success(function (response) {
							var data = response.data;
							try {
								// Interceptors
								angular.forEach(AI, function (interceptor) {
									$AP.interceptors[interceptor](this);
								}, response);
								// Filters
								angular.forEach(AF, function (filter, dataName) {
									this[dataName] = $AP.filters(filter)(this[dataName]);
								}, data);
								// Cache
								if (key) {
									this.cache.put(key, data);
								}

								deffered.resolve(data);
							} catch (errorObject) {
								// 拦截器产生的业务级错误异常对象
								console.warn(errorObject);
								deffered.reject(errorObject);
							}
						}.bind(this)).error(function () {
							deffered.reject(new Error('Connection error.'));
						});
					}

					return deffered.promise;
				};

				return {
					use: function (APIName) {
						if ($AP.has(APIName)) {
							return $AP.APIs[APIName];
						} else {
							throw new Error("No matched API named " + APIName);
						}
					},
					cache: $AP.cache,
					filter: function (name, filter) {
						$AP.filters[name] = filter;
					},
					interceptor: function (name, interceptor) {
						$AP.interceptors[name] = interceptor;
					},
					API: API,
					setAPIOrigin: function (url) {
						$AP.APIOrigin = url;
						$rootScope.ocAPI.origin = url;
					},
					getNow: $rootScope.ocAPI.getNow
				};
			}
		];
	}]);
}(angular));
